package org.azdroid.kit.net;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerPNames;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.azdroid.kit.util.HttpHelper;
import org.azdroid.kit.util.NetworkHelper;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

/**
 * <em>Http连接网络，post get 发送数据并接收返回数据.<em>
 *
 * @author dai.rui.lin
 */
public class HttpAsClient implements Runnable {
	/**
	 * requestMethod
	 */
	public static final byte REQUEST_MOETHOD_GET = (byte) 1;
	public static final byte REQUEST_MOETHOD_POST = (byte) 2;

    /**
     * 联网超时时间
     */
    private static final int TIMEOUT_COMMECTION = 1000 * 30;
    /**
     * 联网数据读取超时时间
     */
    private static final int TIMEOUT_SOCKET =  1000 * 60;
    ;
    static String TAG = "HttpAsClient";
    /**
     * 异常信息
     */
    protected Exception httpException = null;
    protected State mState;
    /**
     * Thread 开关
     */
    boolean running = false;
    int mCount;
    private String mUrl;
    /**
     * 请求方法
     */
    private byte REQUEST_MOETHOD;
    /**
     * 通知接口,负责数据传递。
     */
    private ResultListener resultListener;
    /**
     * 数据发送对象
     */
    private List<NameValuePair> sendData = null;
    /**
     * Context
     */
    private Context mContext;
    /**
     * 任务ID
     */
    private int mTaskId;
    private boolean debug = true;
    /**
     * 请求编码格式
     */
    private String mEncode = "utf-8";

    /**
     * 构造方法，默认GET请求方式，数据必须绑定URL进行传递。
     *
     * @param jobid   任务id
     * @param url     联网URL
     * @param context Context
     */
    public HttpAsClient(int taskId, String url, Context context) {
        mTaskId = taskId;
        mUrl = url;
        mContext = context;
        REQUEST_MOETHOD = REQUEST_MOETHOD_POST;
        mState = State.INIT;
    }

    /**
     * 构造方法，默认POST请求方式。
     *
     * @param jobid          任务ID
     * @param url            联网URL
     * @param context        Context
     * @param nameValuePairs 发送数据内容(List<NameValuePair>)
     */
    public HttpAsClient(int taskid, String url, Context context,
                        List<NameValuePair> send) {
        mTaskId = taskid;
        mUrl = url;
        mContext = context;
        REQUEST_MOETHOD = REQUEST_MOETHOD_GET;
        sendData = send;
        mState = State.INIT;
    }

    /**
     * 关闭流方法
     *
     * @param is InputStream 输入流
     */
    public static void closeIO(InputStream is) {
        try {
            if (is != null) {
                is.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        is = null;
    }

    /**
     *
     * */
    public static byte[] readStreamForBytes(InputStream is) throws IOException {
        byte[] byteBuffer;
        try {
            try {
                int len = (int) is.available();
                if (len > 0) {
                    byteBuffer = new byte[len];
                    int done = 0;
                    while (done < len) {
                        done += is.read(byteBuffer, done, len - done);
                    }
                } else {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    byte[] buffer = new byte[512];
                    int count;
                    while ((count = is.read(buffer)) >= 0) {
                        bos.write(buffer, 0, count);
                    }

                    byteBuffer = bos.toByteArray();
                    if (bos != null) {
                        bos.close();
                    }
                }
            } finally {
                is.close();
            }
        } finally {
        }
        return byteBuffer;
    }

    /**
     * 连接网络并下载数据
     *
     * @return String File
     */
    public static String doHttpRequestGetApk(String url) {
        if (url == null || url.equals("null")) {
            return null;
        }
        InputStream in = null;
        String relust = "";
        try {
            //
            BasicHttpParams httpParameters = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParameters, 3000);//
            HttpConnectionParams.setSoTimeout(httpParameters, 5000);
            //
            HttpClient httpclient = new DefaultHttpClient(httpParameters);
            HttpGet request = new HttpGet(url);
            // request.setHeader("version", SystemDB.MOBILE_VERSION);

            HttpResponse response = httpclient.execute(request);
            in = response.getEntity().getContent();

            FileOutputStream fileOutputStream = null;
            File file = null;
            String apkName = System.currentTimeMillis() + ".apk";

            if (in != null) {

                file = new File(Environment.getExternalStorageDirectory(),
                        apkName);
                fileOutputStream = new FileOutputStream(file);

                byte[] buf = new byte[1024];
                int ch = -1;
                while ((ch = in.read(buf)) != -1) {
                    fileOutputStream.write(buf, 0, ch);
                }
                relust = file.getPath();
            }
            fileOutputStream.flush();
            if (fileOutputStream != null) {
                fileOutputStream.close();
            }

            request.abort();
        } catch (Exception ex) {
            ex.printStackTrace();
            // ex.printStackTrace();

            System.gc();
            return null;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }
        return relust;
    }

    /**
     * 连接网络并下载数据
     *
     * @return byte[]
     */
    protected static byte[] doHttpRequestGet(String url) {
        if (url == null || url.equals("null")) {
            return null;
        }
        if (url == null || (url.indexOf("http://") <= -1)
                || (url.indexOf(".png") <= -1)) {
            return null;
        }
        InputStream in = null;
        byte buf[] = null;
        try {
            //
            BasicHttpParams httpParameters = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParameters, 55000);//
            HttpConnectionParams.setSoTimeout(httpParameters, 55000);
            //
            HttpClient httpclient = new DefaultHttpClient(httpParameters);
            HttpGet request = new HttpGet(url);
            // request.setHeader("version", SystemDB.MOBILE_VERSION);

            HttpResponse response = httpclient.execute(request);
            if (response.getStatusLine().getStatusCode() == 200) {
                in = response.getEntity().getContent();
                buf = HttpHelper.readStream(in);
                request.abort();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            System.gc();
            return null;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }
        return buf;
    }

    public String getmEncode() {
        return mEncode;
    }

    public void setmEncode(String mEncode) {
        this.mEncode = mEncode;
    }

    protected int getTaskId() {
        return mTaskId;
    }

    /**
     * 设置HTTP请求方式,HttpStatus.java
     *
     * @param opt
     */
    public void setRquestMethod(byte opt) {
        REQUEST_MOETHOD = opt;
    }

    @Override
    public synchronized void run() {
        p("run start...");
        running = true;
        mCount = 0;
        while (running) {
            networkExchange();
        }
        p("run game over...");
    }

    protected void p(String msg) {
        if (isDebug())
            Log.d(TAG, msg);
    }

    protected void p(String tag, String msg) {
        if (isDebug())
            Log.d(tag, msg);
    }

    /**
     * 联网处理主体方法
     */
    private void networkExchange() {
        p("networkExchange....");
        byte bytes[] = null;
        long tx = 0;
        if (NetworkHelper.isNetworkAvailable(mContext)) {
            if (REQUEST_MOETHOD ==REQUEST_MOETHOD_GET) {
                bytes = doRequestGet(mUrl);
            } else if (REQUEST_MOETHOD == REQUEST_MOETHOD_POST) {
                bytes = doRequestPost(mUrl, sendData, tx);
            }
        } else {
            mState = State.NONET;
        }

        if (resultListener != null) {
            processResult(bytes);
        }
        running = false;
        p("networkExchange..exit");
    }

    /**
     * 以GET方式发送数据，数据内容大小有限制，并接收返回数据。
     */
    private final byte[] doRequestGet(String url) {
        p("doRequestGet.....");
        InputStream in = null;
        byte buf[] = null;
        try {
            //
            BasicHttpParams httpParameters = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParameters,
                    TIMEOUT_COMMECTION);//
            HttpConnectionParams.setSoTimeout(httpParameters, TIMEOUT_SOCKET);
            //
            HttpClient httpclient = new DefaultHttpClient(httpParameters);
            p("url :" + url);
            HttpGet request = new HttpGet(url);
            mCount++;
            request.setHeader("Accept", "application/json");
            request.setHeader("response", "application/json");
            //
            HttpResponse response = httpclient.execute(request);
            if (response.getStatusLine().getStatusCode() == 200) {

                HttpEntity mEntity = response.getEntity();
                in = mEntity.getContent();
                Header mEncode = mEntity.getContentEncoding();
                if (mEncode != null && mEncode.getValue().equals("gzip")) {
                    buf = HttpHelper.readGZIPInputStream(in);
                } else {
                    buf = HttpHelper.readStream(in);
                }
            }
            // 释放资源
            mState = State.SUCC;
            request.abort();

        } catch (java.net.UnknownHostException ue) {
            ue.printStackTrace();
            System.gc();
            httpException = ue;
            running = false;
            mState = State.FAIL;
            p("UnknownHostException...");

        } catch (Exception ex) {
            p("exception...");
            ex.printStackTrace();
            httpException = ex;
            running = false;
            mState = State.FAIL;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return buf;
    }
    
    /**
     * HTTPS请求方法
     * @param url
     * @param send
     * @return
     */
    protected byte [] doHttpsRequestPost(String url,List<NameValuePair> send){
    	byte[] result = null;
		ClientConnectionManager clientConnectionManager = null;
		HttpContext context = null;
		HttpParams params = null;

		SchemeRegistry schemeRegistry = new SchemeRegistry();
		schemeRegistry.register(new Scheme("http", PlainSocketFactory
				.getSocketFactory(), 80));
		schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(),
				443));
		params = new BasicHttpParams();
		params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 1);
		params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE,
				new ConnPerRouteBean(1));
		params.setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
		HttpProtocolParams.setContentCharset(params, "utf-8");
		HttpConnectionParams.setConnectionTimeout(params, 3000);
		HttpConnectionParams.setSoTimeout(params, 5000);
		CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
		credentialsProvider.setCredentials(new AuthScope("example.com",
				AuthScope.ANY_PORT), new UsernamePasswordCredentials(
				"UserNameHere", "UserPasswordHere"));
		clientConnectionManager = new ThreadSafeClientConnManager(params,
				schemeRegistry);

		context = new BasicHttpContext();
		context.setAttribute("http.auth.credentials-provider",
				credentialsProvider);

		try {
			HttpPost post = new HttpPost(url);
			if (send != null && send.size() > 0) {
				try {
					UrlEncodedFormEntity entity = new UrlEncodedFormEntity(
							send, "UTF_8");
					post.setEntity(entity);
				} catch (UnsupportedEncodingException e1) {
					e1.printStackTrace();
				}
			}
			DefaultHttpClient client = new DefaultHttpClient(
					clientConnectionManager, params);
			try {
				HttpResponse response = client.execute(post);
				if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
					result = HttpHelper.readStream(response.getEntity()
							.getContent());
				}
			} finally {

			}

			mState = State.SUCC;
		} catch (java.net.UnknownHostException ue) {
			ue.printStackTrace();
			System.gc();
			httpException = ue;
			running = false;
			mState = State.FAIL;
		} catch (Exception ex) {
			ex.printStackTrace();
			httpException = ex;
			running = false;
			mState = State.FAIL;
		} finally {
			if (clientConnectionManager != null) {
				clientConnectionManager.shutdown();
			}
		}
		return result;
    }

    /**
     * 以POST方式发送数据，并接受返回数据
     */
    private byte[] doRequestPost(String url, List<NameValuePair> send, long tx) {
        p("doRequestPost.....");
        BasicHttpParams httpParameters = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParameters,
                TIMEOUT_COMMECTION);//
        HttpConnectionParams.setSoTimeout(httpParameters, TIMEOUT_SOCKET);
        HttpClient httpclient = new DefaultHttpClient(httpParameters);
        HttpPost httppost = new HttpPost(url);
        p("url: " + url);
        mCount++;
        // httppost.setHeader("Accept-Encoding", "gzip,deflate");
        httppost.setHeader("Accept", "application/json");
        httppost.setHeader("response", "application/json");
        InputStream in = null;
        byte buf[] = null;

        try {
            if (send != null) {
                List<NameValuePair> mSend = send;
                UrlEncodedFormEntity mUm = new UrlEncodedFormEntity(mSend, mEncode);
                p("send-data: " + mUm.toString());
                tx = mUm.toString().getBytes().length;
                httppost.setEntity(mUm);

            }
            HttpResponse response = httpclient.execute(httppost);
            if (response.getStatusLine().getStatusCode() == 200) {
                HttpEntity mEntity = response.getEntity();
                in = mEntity.getContent();
                Header mEncode = mEntity.getContentEncoding();
                if (mEncode != null && mEncode.getValue().equals("gzip")) {
                    buf = HttpHelper.readGZIPInputStream(in);
                } else {
                    buf = HttpHelper.readStream(in);
                }
            }
            // 释放资源
            httppost.abort();
            mState = State.SUCC;
        } catch (java.net.UnknownHostException ue) {
            ue.printStackTrace();
            System.gc();
            httpException = ue;
            running = false;
            mState = State.FAIL;
        } catch (Exception ex) {
            ex.printStackTrace();
            httpException = ex;
            running = false;
            mState = State.FAIL;

        }
        return buf;

    }

    /**
     * 返回结果并通知
     */
    protected synchronized void processResult(byte bytes[]) {
        p("processResult......");

        if (resultListener instanceof DataResultListener) {
            DataResultListener callback = (DataResultListener) resultListener;
            if (httpException != null) {
                callback.onResultFail(mState, mTaskId, httpException);
            } else {
                callback.onResultSucc(mState, mTaskId, bytes);
            }

        }

    }

    /**
     * @return resultListener 获取数据通知接口
     */
    public ResultListener getResultListener() {
        return resultListener;
    }

    /**
     * 设置数据返回通知接口
     *
     * @param resultListener 数据通知接口
     */
    public void setResultListener(ResultListener resultListener) {
        this.resultListener = resultListener;
    }

    /**
     * 设置POST发送数据对象
     *
     * @param sendListNameValuePair 发送数据内容
     */
    public void setSendListNameValuePair(List<NameValuePair> send) {
        this.sendData = send;
    }

    /**
     * 是否开启debug信息输出
     *
     * @return isdebug
     */
    public boolean isDebug() {
        return debug;
    }

    /**
     * 设置debug输出调试信息
     *
     * @param debug
     */
    public void setDebug(boolean debug) {
        this.debug = debug;
    }

}
